package cn.wenhaha.common.db;

import cn.hutool.core.util.StrUtil;
import cn.wenhaha.common.bean.AppInstallFinish;
import cn.wenhaha.common.config.GlobalApp;
import cn.wenhaha.common.db.bean._MappingKit;
import cn.wenhaha.common.utils.spring.SpringUtils;
import com.jfinal.plugin.activerecord.ActiveRecordPlugin;
import com.jfinal.plugin.activerecord.IDataSourceProvider;
import com.jfinal.template.source.ClassPathSourceFactory;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.DependsOn;
import org.springframework.context.event.EventListener;
import org.springframework.core.annotation.Order;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
import org.springframework.stereotype.Component;

import javax.sql.DataSource;
import java.sql.Connection;
import java.util.EventObject;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * 动态数据源
 * --------
 *
 * @author ：wyndem
 * @Date ：Created in 2022-03-19 13:55
 */
@Slf4j
@Component
@DependsOn({"global"})
public class DynamicDataSource extends AbstractRoutingDataSource implements IDataSourceProvider {

    private Map<Object, Object> targetDataSources=new HashMap<>(1);
    public  final Object dataSourceName = new Object();
    private volatile AtomicBoolean isInit=new AtomicBoolean(false);

    private  ActiveRecordPlugin activeRecordPlugin;


    public DynamicDataSource() {
        HikariDataSource hikariDataSource = new HikariDataSource();
        targetDataSources.put(dataSourceName,hikariDataSource);
        setDefaultTargetDataSource(hikariDataSource);
        setTargetDataSources(targetDataSources);
        refresh();
    }

    @Override
    protected Object determineCurrentLookupKey() {
        return dataSourceName;
    }

    @EventListener(AppInstallFinish.class)
    @Order(-99)
    public void handler(AppInstallFinish event) {
        log.info("用户安装完成");
        refresh();
    }


    /**
     * <p>
     *    刷新数据源
     * </p>
     * @Author: Wyndem
     * @DateTime: 2022-03-19 14:17
     */
    public  void refresh(){
        GlobalApp globalApp = GlobalApp.getInstance(true);
        if (globalApp==null || globalApp.getFlag()==null){
            log.debug("数据暂末配置，不加载数据源...");
            return;
        }
        if(!isInit.compareAndSet(false,true)) {
            return;
        }


        HikariConfig config = new HikariConfig();

        if ("0".equals(globalApp.getType().toString())){
            String url="jdbc:mysql://{}:{}/{}?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&serverTimezone=GMT%2B8";
            config.setJdbcUrl(StrUtil.format(url,globalApp.getHost(),globalApp.getPort(),globalApp.getDatabase()));
            config.setUsername(globalApp.getUsername());
            config.setPassword(globalApp.getPassword());
        }else {
            config.setJdbcUrl(globalApp.getLink());
        }

        config.addDataSourceProperty("cachePrepStmts", "true");
        config.addDataSourceProperty("prepStmtCacheSize", "250");
        config.addDataSourceProperty("prepStmtCacheSqlLimit", "2048");
        config.setMaxLifetime(30000);
        config.setConnectionTimeout(60000);
        config.setValidationTimeout(3000);
        config.setIdleTimeout(500000);
        config.setIdleTimeout(500000);
        config.setMinimumIdle(10);
        config.setMaximumPoolSize(30);
        HikariDataSource hikariDataSource = new HikariDataSource(config);
        setDefaultTargetDataSource(hikariDataSource);
        targetDataSources.put(dataSourceName,hikariDataSource);
        afterPropertiesSet();
        if(activeRecordPlugin!=null){
            activeRecordPlugin.stop();
        }
        activeRecordPlugin=initActiveRecordPlugin();
    }


    public ActiveRecordPlugin initActiveRecordPlugin() {
        ActiveRecordPlugin arp = new ActiveRecordPlugin(getDataSource());
        arp.setTransactionLevel(Connection.TRANSACTION_READ_COMMITTED);
        _MappingKit.mapping(arp);
        arp.setShowSql(false);
        arp.setDevMode(false);

        arp.getEngine().setSourceFactory(new ClassPathSourceFactory());
        arp.addSqlTemplate("/sql/all_sqls.sql");
        // 必须手动调用start
        arp.start();
        return arp;
    }




    @Override
    public DataSource getDataSource() {
        return this;
    }
}
